package maple.thelittleredbook.recommendation.service;

import lombok.extern.slf4j.Slf4j;
import maple.thelittleredbook.content.dto.ContentViewDTO;
import maple.thelittleredbook.content.entity.Content;
import maple.thelittleredbook.content.entity.Image;
import maple.thelittleredbook.content.entity.Video;
import maple.thelittleredbook.content.mapper.ImageMapper;
import maple.thelittleredbook.content.mapper.VideoMapper;
import maple.thelittleredbook.recommendation.entity.ContentFeature;
import maple.thelittleredbook.recommendation.mapper.ContentFeatureMapper;
import maple.thelittleredbook.recommendation.mapper.RecommendationMapper;
import maple.thelittleredbook.user.entity.User;
import maple.thelittleredbook.user.entity.UserProfile;
import maple.thelittleredbook.user.mapper.UserMapper;
import maple.thelittleredbook.user.mapper.UserProfileMapper;
import maple.thelittleredbook.interaction.service.AsyncUserBehaviorService;
import maple.thelittleredbook.interaction.entity.Like;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 推荐服务
 * 负责个性化内容推荐算法的实现
 */
@Slf4j
@Service
public class RecommendationService {

    private final RecommendationMapper recommendationMapper;
    private final UserProfileMapper userProfileMapper;
    private final UserMapper userMapper;
    private final ContentFeatureMapper contentFeatureMapper;

    private final RecommendationCacheService cacheService;
    private final AsyncUserBehaviorService asyncUserBehaviorService;

    private final ImageMapper imageMapper;
    private final VideoMapper videoMapper;

    // 推荐算法配置
    @Value("${recommendation.similarity-threshold}")
    private double similarityThreshold;

    @Value("${recommendation.neutral-user-threshold}")
    private double neutralUserThreshold;

    @Value("${recommendation.max-pages}")
    private int maxPages;

    @Value("${recommendation.page-size}")
    private int pageSize;

    @Value("${recommendation.result-size}")
    private int resultSize;

    @Autowired
    public RecommendationService(RecommendationMapper recommendationMapper,
                                 UserProfileMapper userProfileMapper,
                                 UserMapper userMapper,
                                 ContentFeatureMapper contentFeatureMapper,
                                 RecommendationCacheService cacheService,
                                 AsyncUserBehaviorService asyncUserBehaviorService, ImageMapper imageMapper, VideoMapper videoMapper) {
        this.recommendationMapper = recommendationMapper;
        this.userProfileMapper = userProfileMapper;
        this.userMapper = userMapper;
        this.contentFeatureMapper = contentFeatureMapper;
        this.cacheService = cacheService;
        this.asyncUserBehaviorService = asyncUserBehaviorService;
        this.imageMapper = imageMapper;
        this.videoMapper = videoMapper;
    }

    /**
     * 获取用户的下一个推荐内容
     *
     * @param userId 用户ID
     * @return 推荐内容DTO，如果没有更多推荐则返回null
     */
    public ContentViewDTO getNextRecommendation(Long userId) {
        if (userId == null) {
            log.warn("用户ID为空，返回null");
            return null;
        }

        ContentViewDTO recommendation = null;

        try {
            // 1. 尝试从缓存获取推荐
            ContentViewDTO cachedRecommendation = cacheService.getNextRecommendation(userId);

            if (cachedRecommendation != null) {
                // 更新用户相关状态（如isLiked）
                enhanceWithUserState(cachedRecommendation, userId);
                recommendation = cachedRecommendation;
                log.debug("从缓存获取推荐成功: userId={}, contentId={}", userId, recommendation.getId());
            } else {
                // 2. 缓存为空，重新计算推荐
                List<ContentViewDTO> newRecommendations = calculateRecommendations(userId);

                if (newRecommendations.isEmpty()) {
                    log.info("无法为用户生成推荐内容: userId={}", userId);
                    return null;
                }

                // 3. 缓存新的推荐结果
                cacheService.cacheRecommendations(userId, newRecommendations);

                // 4. 返回第一个推荐
                ContentViewDTO firstRecommendation = cacheService.getNextRecommendation(userId);
                if (firstRecommendation != null) {
                    enhanceWithUserState(firstRecommendation, userId);
                    recommendation = firstRecommendation;
                    log.debug("重新计算推荐成功: userId={}, contentId={}", userId, recommendation.getId());
                }
            }

        } catch (Exception e) {
            log.error("获取推荐内容失败: userId={}", userId, e);
            recommendation = getFallbackRecommendation(userId);
        }

        // 5. 最后记录浏览行为（确保在所有业务逻辑完成后调用）
        if (recommendation != null) {
            try {
                asyncUserBehaviorService.processViewBehaviorAsync(userId, recommendation.getId());
                log.debug("异步记录推荐浏览行为: userId={}, contentId={}", userId, recommendation.getId());
            } catch (Exception e) {
                log.error("记录推荐浏览行为失败: userId={}, contentId={}", userId, recommendation.getId(), e);
                // 不影响推荐结果返回，只记录错误日志
            }
        }

        return recommendation;
    }

    /**
     * 计算用户推荐内容
     */
    private List<ContentViewDTO> calculateRecommendations(Long userId) {
        try {
            // 1. 获取用户画像
            UserProfile userProfile = getUserProfile(userId);

            if (userProfile == null) {
                log.debug("用户画像不存在，使用兜底策略: userId={}", userId);
                return getFallbackRecommendations(userId);
            }

            // 2. 判断用户类型
            if (isNeutralUser(userProfile)) {
                log.debug("中性用户，返回热门内容: userId={}", userId);
                return getNeutralUserRecommendations(userId);
            }

            // 3. 个性化推荐
            log.debug("个性化用户，执行相似度计算: userId={}", userId);
            return getPersonalizedRecommendations(userId, userProfile);

        } catch (Exception e) {
            log.error("计算推荐内容失败: userId={}", userId, e);
            return getFallbackRecommendations(userId);
        }
    }

    /**
     * 获取用户画像
     */
    private UserProfile getUserProfile(Long userId) {
        try {
            return userProfileMapper.selectByUserId(userId);
        } catch (Exception e) {
            log.error("获取用户画像失败: userId={}", userId, e);
            return null;
        }
    }

    /**
     * 判断是否为中性用户
     */
    private boolean isNeutralUser(UserProfile userProfile) {
        if (userProfile == null) {
            return true;
        }

        try {
            double magnitude = calculateUserVectorMagnitude(userProfile);
            boolean isNeutral = magnitude < neutralUserThreshold;

            log.debug("用户画像向量模长: {}, 阈值: {}, 是否中性: {}", magnitude, neutralUserThreshold, isNeutral);
            return isNeutral;

        } catch (Exception e) {
            log.error("判断中性用户失败: userId={}", userProfile.getUserId(), e);
            return true; // 异常时认为是中性用户
        }
    }

    /**
     * 计算用户画像向量模长
     */
    private double calculateUserVectorMagnitude(UserProfile userProfile) {
        double sum = 0.0;

        sum += square(userProfile.getDim1());
        sum += square(userProfile.getDim2());
        sum += square(userProfile.getDim3());
        sum += square(userProfile.getDim4());
        sum += square(userProfile.getDim5());
        sum += square(userProfile.getDim6());
        sum += square(userProfile.getDim7());
        sum += square(userProfile.getDim8());

        return Math.sqrt(sum);
    }

    /**
     * 安全的平方计算
     */
    private double square(BigDecimal value) {
        if (value == null) {
            return 0.0;
        }
        double doubleValue = value.doubleValue();
        return doubleValue * doubleValue;
    }

    /**
     * 中性用户推荐策略
     */
    private List<ContentViewDTO> getNeutralUserRecommendations(Long userId) {
        try {
            List<Content> hotContents = recommendationMapper.selectUnviewedContents(userId, 0, resultSize);
            return convertToContentViewDTOs(hotContents, userId);
        } catch (Exception e) {
            log.error("获取中性用户推荐失败: userId={}", userId, e);
            return getFallbackRecommendations(userId);
        }
    }

    /**
     * 个性化推荐策略
     */
    private List<ContentViewDTO> getPersonalizedRecommendations(Long userId, UserProfile userProfile) {
        List<ContentViewDTO> recommendations = new ArrayList<>();

        try {
            // 分页查找符合相似度阈值的内容
            for (int page = 1; page <= maxPages && recommendations.size() < resultSize; page++) {
                int offset = (page - 1) * pageSize;

                // 获取候选内容
                List<Content> candidates = recommendationMapper.selectUnviewedContents(userId, offset, pageSize);

                if (candidates.isEmpty()) {
                    log.debug("第{}页无更多候选内容，停止查找: userId={}", page, userId);
                    break;
                }

                // 计算相似度并筛选
                for (Content content : candidates) {
                    if (recommendations.size() >= resultSize) {
                        break;
                    }

                    double similarity = calculateContentSimilarity(userProfile, content.getId());

                    if (similarity >= similarityThreshold) {
                        ContentViewDTO dto = convertToContentViewDTO(content, userId);
                        recommendations.add(dto);
                        log.debug("添加相似内容: userId={}, contentId={}, similarity={}",
                                userId, content.getId(), similarity);
                    }
                }

                log.debug("第{}页处理完成: userId={}, 当前推荐数={}", page, userId, recommendations.size());
            }

            // 如果推荐数不足，用高点赞内容补齐
            if (recommendations.size() < resultSize) {
                fillWithFallbackContents(userId, recommendations);
            }

            return recommendations;

        } catch (Exception e) {
            log.error("个性化推荐计算失败: userId={}", userId, e);
            return getFallbackRecommendations(userId);
        }
    }

    /**
     * 计算内容与用户画像的相似度
     */
    private double calculateContentSimilarity(UserProfile userProfile, Long contentId) {
        try {
            // 获取内容特征向量
            ContentFeature contentFeature = contentFeatureMapper.selectCompletedFeatureByContentId(contentId);

            if (contentFeature == null) {
                log.debug("内容特征不存在: contentId={}", contentId);
                return 0.0;
            }

            // 计算余弦相似度
            return calculateCosineSimilarity(userProfile, contentFeature);

        } catch (Exception e) {
            log.error("计算内容相似度失败: contentId={}", contentId, e);
            return 0.0;
        }
    }

    /**
     * 计算余弦相似度
     */
    private double calculateCosineSimilarity(UserProfile userProfile, ContentFeature contentFeature) {
        try {
            // 计算向量内积
            double dotProduct = 0.0;
            dotProduct += multiply(userProfile.getDim1(), contentFeature.getDim1());
            dotProduct += multiply(userProfile.getDim2(), contentFeature.getDim2());
            dotProduct += multiply(userProfile.getDim3(), contentFeature.getDim3());
            dotProduct += multiply(userProfile.getDim4(), contentFeature.getDim4());
            dotProduct += multiply(userProfile.getDim5(), contentFeature.getDim5());
            dotProduct += multiply(userProfile.getDim6(), contentFeature.getDim6());
            dotProduct += multiply(userProfile.getDim7(), contentFeature.getDim7());
            dotProduct += multiply(userProfile.getDim8(), contentFeature.getDim8());

            // 计算用户向量模长
            double userMagnitude = calculateUserVectorMagnitude(userProfile);

            // 计算内容向量模长
            double contentMagnitude = calculateContentVectorMagnitude(contentFeature);

            // 计算余弦相似度
            if (userMagnitude == 0.0 || contentMagnitude == 0.0) {
                return 0.0;
            }

            return dotProduct / (userMagnitude * contentMagnitude);

        } catch (Exception e) {
            log.error("计算余弦相似度失败", e);
            return 0.0;
        }
    }

    /**
     * 计算内容特征向量模长
     */
    private double calculateContentVectorMagnitude(ContentFeature contentFeature) {
        double sum = 0.0;

        sum += square(contentFeature.getDim1());
        sum += square(contentFeature.getDim2());
        sum += square(contentFeature.getDim3());
        sum += square(contentFeature.getDim4());
        sum += square(contentFeature.getDim5());
        sum += square(contentFeature.getDim6());
        sum += square(contentFeature.getDim7());
        sum += square(contentFeature.getDim8());

        return Math.sqrt(sum);
    }

    /**
     * 安全的BigDecimal乘法
     */
    private double multiply(BigDecimal a, BigDecimal b) {
        if (a == null || b == null) {
            return 0.0;
        }
        return a.doubleValue() * b.doubleValue();
    }

    /**
     * 用兜底内容补齐推荐列表
     */
    private void fillWithFallbackContents(Long userId, List<ContentViewDTO> recommendations) {
        try {
            int needed = resultSize - recommendations.size();
            if (needed <= 0) {
                return;
            }

            // 获取已推荐的内容ID，避免重复
            List<Long> existingIds = new ArrayList<>();
            for (ContentViewDTO dto : recommendations) {
                existingIds.add(dto.getId());
            }

            // 获取热门内容进行补齐
            List<Content> fallbackContents = recommendationMapper.selectUnviewedContents(userId, 0, needed * 2);

            for (Content content : fallbackContents) {
                if (recommendations.size() >= resultSize) {
                    break;
                }

                // 避免重复推荐
                if (!existingIds.contains(content.getId())) {
                    ContentViewDTO dto = convertToContentViewDTO(content, userId);
                    recommendations.add(dto);
                }
            }

            log.debug("补齐推荐内容完成: userId={}, 最终推荐数={}", userId, recommendations.size());

        } catch (Exception e) {
            log.error("补齐推荐内容失败: userId={}", userId, e);
        }
    }

    /**
     * 兜底推荐策略
     */
    private List<ContentViewDTO> getFallbackRecommendations(Long userId) {
        try {
            List<Content> hotContents = recommendationMapper.selectGlobalHotContents(resultSize);
            return convertToContentViewDTOs(hotContents, userId);
        } catch (Exception e) {
            log.error("兜底推荐失败: userId={}", userId, e);
            return new ArrayList<>();
        }
    }

    /**
     * 单个兜底推荐
     */
    private ContentViewDTO getFallbackRecommendation(Long userId) {
        List<ContentViewDTO> fallbackList = getFallbackRecommendations(userId);
        return fallbackList.isEmpty() ? null : fallbackList.get(0);
    }

    /**
     * 批量转换Content到ContentViewDTO
     */
    private List<ContentViewDTO> convertToContentViewDTOs(List<Content> contents, Long userId) {
        List<ContentViewDTO> dtos = new ArrayList<>();

        for (Content content : contents) {
            try {
                ContentViewDTO dto = convertToContentViewDTO(content, userId);
                dtos.add(dto);
            } catch (Exception e) {
                log.error("转换ContentViewDTO失败: contentId={}", content.getId(), e);
            }
        }

        return dtos;
    }

    /**
     * 转换Content到ContentViewDTO
     */
    private ContentViewDTO convertToContentViewDTO(Content content, Long userId) {
        ContentViewDTO dto = new ContentViewDTO();

        // 基础字段复制
        dto.setId(content.getId());
        dto.setUserId(content.getUserId());
        dto.setContentType(content.getContentType());
        dto.setTitle(content.getTitle());
        dto.setTextContent(content.getTextContent());
        dto.setCoverUrl(content.getCoverUrl());
        dto.setLikeCount(content.getLikeCount());
        dto.setCommentCount(content.getCommentCount());
        dto.setViewCount(content.getViewCount());
        dto.setIsPublished(content.getIsPublished());
        dto.setCreatedAt(content.getCreatedAt());
        dto.setUpdatedAt(content.getUpdatedAt());

        // 设置内容发布用户信息
        try {
            User contentUser = userMapper.selectById(content.getUserId());
            if (contentUser != null) {
                dto.setUsername(contentUser.getUsername());
                dto.setUserAvatar(contentUser.getAvatar());
            }
        } catch (Exception e) {
            log.error("获取内容用户信息失败: contentId={}, userId={}", content.getId(), content.getUserId(), e);
            dto.setUsername("未知用户");
            dto.setUserAvatar(null);
        }

        // 媒体信息暂时设置为空，后续如需要可以扩展
        dto.setImages(new ArrayList<>());
        dto.setVideos(new ArrayList<>());

        return dto;
    }

    /**
     * 增强DTO的用户相关状态 - 修改版本
     */
    private void enhanceWithUserState(ContentViewDTO dto, Long userId) {
        try {
            // 检查用户是否点赞
            Like likeStatus = asyncUserBehaviorService.getLikeStatus(userId, dto.getId(), "CONTENT");
            dto.setIsLiked(likeStatus != null);

            // 查询并设置图片列表
            List<Image> images = imageMapper.selectByContentId(dto.getId());
            List<ContentViewDTO.ImageDTO> imageDTOs = images.stream()
                    .map(image -> {
                        ContentViewDTO.ImageDTO imageDTO = new ContentViewDTO.ImageDTO();
                        imageDTO.setId(image.getId());
                        imageDTO.setImageUrl(image.getImageUrl());
                        imageDTO.setCreatedAt(image.getCreatedAt());
                        return imageDTO;
                    })
                    .collect(Collectors.toList());
            dto.setImages(imageDTOs);

            // 查询并设置视频列表
            List<Video> videos = videoMapper.selectByContentId(dto.getId());
            List<ContentViewDTO.VideoDTO> videoDTOs = videos.stream()
                    .map(video -> {
                        ContentViewDTO.VideoDTO videoDTO = new ContentViewDTO.VideoDTO();
                        videoDTO.setId(video.getId());
                        videoDTO.setVideoUrl(video.getVideoUrl());
                        videoDTO.setCreatedAt(video.getCreatedAt());
                        return videoDTO;
                    })
                    .collect(Collectors.toList());
            dto.setVideos(videoDTOs);

        } catch (Exception e) {
            log.error("增强用户状态失败: userId={}, contentId={}", userId, dto.getId(), e);
            dto.setIsLiked(false); // 默认未点赞
            dto.setImages(new ArrayList<>()); // 默认空列表
            dto.setVideos(new ArrayList<>()); // 默认空列表
        }
    }

    /**
     * 刷新用户推荐缓存
     * 当用户行为发生变化时调用
     */
    public void refreshUserRecommendationCache(Long userId) {
        try {
            cacheService.refreshRecommendationCache(userId);
            log.debug("刷新用户推荐缓存: userId={}", userId);
        } catch (Exception e) {
            log.error("刷新用户推荐缓存失败: userId={}", userId, e);
        }
    }
}